#pragma once
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include "http_protocol.hpp"
#include "data_manage.hpp"

extern cloud::data_manage *dm;

namespace cloud
{
    class service
    {
    public:
        static Response fill_response(const Request &req)
        {
            bool download_flag = false;
            if(req._url.size() > 10)
            {
                if(req._url.substr(0, 10) == "/download/")
                    download_flag = true;
            }

            if(req._url == "/")
            {
                Response res = get_index();
                return res;
            }
            else if(req._method == "GET" && req._url == "/upload")
            {
                Response res = get_upload();
                return res;
            }
            else if(req._method == "POST" && req._url == "/upload")
            {
                // std::cout << "捕捉到upload" << std::endl;
                // 文件上传
                std::string content = req._content;
                upload(content);
                Response res = get_upload();
                return res;
            }
            else if(req._url == "/list")
            {
                // 展示文件列表
                // std::cout << "捕捉到list" << std::endl;
                Response res = show_list();
                return res;
            }
            else if(download_flag == true)
            {
                // 下载文件
                // std::cout << "触发下载" << std::endl;
                Response res = download(req);
                return res;
            }
            else if(req._url == "/favicon.ico")
            {
                // 获取图标
                Response res = get_ico();
                return res;
            }
            else
            {
                // 404
                Response res = page_404();
                // Response res;
                return res;
            }
        }

        // 获取主页
        static Response get_index()
        {
            Response res;
            res._heads.push_back("Content-Type: text/html");
            res._content = util::read_file("./web_root/index.html");
            std::string len = "Content-Length: " + std::to_string(res._content.size());
            res._heads.push_back(len);
            return res;
        }

        // 获取上传页面
        static Response get_upload()
        {
            Response res;
            res._heads.push_back("Content-Type: text/html");
            res._content = util::read_file("./web_root/upload.html");
            std::string len = "Content-Length: " + std::to_string(res._content.size());
            res._heads.push_back(len);
            return res;
        }

        // 文件上传
        static void upload(std::string &content)
        {
            // 需要对content中的数据进行分析
            // 剥离出需要的数据

            // ------WebKitFormBoundaryQRFCM6AhXRzuSvXA
            // Content-Disposition: form-data; name="file"; filename="file2.txt"
            // Content-Type: text/plain
            //
            // test
            // 测试
            // ------WebKitFormBoundaryQRFCM6AhXRzuSvXA--
            //

            // 以上是测试的得到的content数据，可以看到第二行有我们要的文件名字
            // 而file2.txt中的测试后面我是没有加换行的，说明浏览器会在其后面添加\r\n
            // 所有我们要截取的数据范围是   空行 --> 倒数第二个\r

            std::string line = util::read_one_line(content, "\r\n");
            line = util::read_one_line(content, "\r\n");//第二行
            size_t start = line.find("filename");
            if(start == std::string::npos)
            {
                // std::cout << "service.hpp upload 未找到filename";
                ERROR("未找到filename");
            }
            size_t end = line.find_last_of('"');
            // 纯文件名，不带路径
            std::string file_name = line.substr(start + 10, end - start - 10);

            // 读到空行，也就是删除空行前面的内容
            while(line != "")
            {
                // std::cout << line << std::endl;
                line = util::read_one_line(content, "\r\n");
            }

            // 找倒数第二个\r的位置
            size_t pos = content.size() - 3;
            while(content[pos] != '\r' && pos >= 0)
            {
                --pos;
            }
            content.erase(pos); // 剩下的content就是我们想要的文件数据！
            //std::cout << "文件数据:" << std::endl;
            //std::cout << content << std::endl;


            std::ofstream ofs;
            std::string path = "./backdir/";
            path += file_name;
            ofs.open(path, std::ios::binary);
            if(ofs.is_open() == false)
            {
                // std::cout << "upload open fail" << std::endl;
                ERROR("文件打开失败 --> %s", path.c_str());
                return;
            }
            ofs.write(&content[0], content.size());
            if(ofs.good() == false)
            {
                // std::cout << "upload write fail" << std::endl;
                ERROR("文件写入失败 --> %s", path.c_str());
            }
            ofs.close();
            struct backup_info info(path);
            dm->insert(info);
            // INFO("upload");
            // info.print();

            INFO("文件上传成功 --> %s", path.c_str());
        }

        // 展示文件列表
        static Response show_list()
        {
            // 从cloud.dat中读取文件信息
            std::vector<backup_info> infos;
            dm->get_all(infos);

            std::stringstream ss;
            ss << R"(<!DOCTYPE html><html lang="zh"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>文件列表</title></head><body><h1 style="font-size: 40px;">文件下载</h1>)";
            for(auto &i : infos)
            {
                std::string file_name = file_util(i._real_path).file_name();
                // 如果href中如果有汉字，那么生成的request须解码
                ss << "<p><a href='" << i._url << "'>" << file_name << "</a> ";
                ss << i._fsize/1024  << "Kb ";
                ss << util::t_to_s(i._mtime) << "</p>";
            }
            ss << R"(<p><a href="/">返回首页</a></p></body></html>)";

            Response res;
            res._content = ss.str();
            res._heads.push_back("Content-Type: text/html");
            std::string len = "Content-Length: " + std::to_string(ss.str().size());
            res._heads.push_back(len);
            return res;
        }

        // 下载文件
        static Response download(const Request &req)
        {
            std::string converted_filename = util::code_convert(req._url.substr(10));
            std::string path = "./backdir/";
            std::string url = "/download/";
            path += converted_filename;
            url += converted_filename;
            //std::cout << "path:" << path << std::endl;

            // 判断文件是否被压缩
            backup_info info;
            dm->get_one_by_url(url, info);
            if(info._pack_flag == true)
            {
                file_util fu(info._pack_path);
                fu.decompress(info._real_path);
                fu.file_remove();
                info._pack_flag = false;
                dm->updata(info);
            }

            Response res;
            res._heads.push_back("Content-Type: application/octet-stream");

            // std::string len = "Content-Length: " + std::to_string(info._fsize);
            // res._heads.push_back(len);

            res._content = util::read_file(path);
            std::string len = "Content-Length: " + std::to_string(res._content.size());
            res._heads.push_back(len);

            return res;
        }

        static Response page_404()
        {
            Response res;
            res._status = "404";
            res._info = "Not Found";
            res._heads.push_back("Content-Type: text/html");
            res._content = util::read_file("./web_root/page_404.html");
            std::string len = "Content-Length: " + std::to_string(res._content.size());
            res._heads.push_back(len);

            return res;
        }

        static Response get_ico()
        {
            Response res;
            //res._heads.push_back("Content-Type: image/x-icon");
            res._content = util::read_file("./web_root/favicon.ico");
            std::string len = "Content-Length: " + std::to_string(res._content.size());
            res._heads.push_back(len);

            return res;
        }
    };
}